home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / comm / term / term34Source.lha / termSound.c < prev    next >
C/C++ Source or Header  |  1993-07-16  |  21KB  |  1,066 lines

  1. /*
  2. **    termSound.c
  3. **
  4. **    Sound support routines
  5. **
  6. **    Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Double buffering chunk size. */
  13.  
  14. #define BUFFER_SIZE    32768
  15.  
  16.     /* Maximum replay volume. */
  17.  
  18. #define MAX_VOLUME    64
  19.  
  20.     /* Stereo/channel sample type. */
  21.  
  22. typedef LONG        SampleType;
  23.  
  24.     /* Channel definitions. */
  25.  
  26. #define SAMPLE_LEFT    2
  27. #define SAMPLE_RIGHT    4
  28. #define SAMPLE_STEREO    6
  29.  
  30.     /* A fixed-point value, 16 bits to the left of
  31.      * the point and 16 to the right. A Fixed is a
  32.      * number of 2**16ths, i.e. 65536ths.
  33.      */
  34.  
  35. typedef LONG        Fixed;
  36.  
  37.     /* Unity = Fixed 1.0 = maximum volume */
  38.  
  39. #define Unity        0x10000L
  40.  
  41.     /* Sample compression modes. */
  42.  
  43. #define sCmpNone    0
  44. #define sCmpFibDelta    1
  45.  
  46.     /* The voice header. */
  47.  
  48. typedef struct
  49. {
  50.     ULONG    oneShotHiSamples,    /* # samples in the high octave 1-shot part */
  51.         repeatHiSamples,    /* # samples in the high octave repeat part */
  52.         samplesPerHiCycle;    /* # samples/cycle in high octave, else 0 */
  53.     UWORD    samplesPerSec;        /* data sampling rate */
  54.     UBYTE    ctOctave,        /* # of octaves of waveforms */
  55.         sCompression;        /* data compression technique used */
  56.     Fixed    volume;            /* playback nominal volume from 0 to Unity
  57.                      * (full volume). Map this value into
  58.                      * the output hardware's dynamic range.
  59.                      */
  60. } Voice8Header;
  61.  
  62.     /* Double-buffering information. */
  63.  
  64. struct BufferInfo
  65. {
  66.     LONG    Size;
  67.     UBYTE    Buffer[BUFFER_SIZE];
  68. };
  69.  
  70.     /* Sound replay information. */
  71.  
  72. struct SoundInfo
  73. {
  74.     UBYTE    Name[MAX_FILENAME_LENGTH];
  75.  
  76.     ULONG    Rate,
  77.         Length,
  78.         Volume;
  79.  
  80.     APTR    SoundData;
  81.  
  82.     APTR    LeftData,
  83.         RightData;
  84. };
  85.  
  86.     /* Local data. */
  87.  
  88. STATIC struct SignalSemaphore    *SoundSemaphore;
  89. STATIC struct SoundInfo        *SoundSlot[SOUND_COUNT];
  90.  
  91.     /* DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst):
  92.      *
  93.      *    Unpack Fibonacci-delta-encoded data.
  94.      */
  95.  
  96. STATIC VOID __regargs
  97. DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst)
  98. {
  99.     STATIC BYTE CodeToDelta[16] = { -34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21 };
  100.  
  101.     BYTE    Value = (BYTE)Src[1];
  102.     UBYTE    Code;
  103.  
  104.         /* Skip the header information. */
  105.  
  106.     Src    += 2;
  107.     Size    -= 2;
  108.  
  109.         /* Run down the chunk... */
  110.  
  111.     while(Size--)
  112.     {
  113.         Code = *Src++;
  114.  
  115.             /* Add the top nibble delta. */
  116.  
  117.         Value += CodeToDelta[Code >> 4];
  118.  
  119.         *Dst++ = Value;
  120.  
  121.             /* Add the bottom nibble delta. */
  122.  
  123.         Value += CodeToDelta[Code & 0xF];
  124.  
  125.         *Dst++ = Value;
  126.     }
  127. }
  128.  
  129.     /* FreeSound(struct SoundInfo *SoundInfo):
  130.      *
  131.      *    Free sound handle and associated data.
  132.      */
  133.  
  134. VOID __regargs
  135. FreeSound(struct SoundInfo *SoundInfo)
  136. {
  137.     FreeVec(SoundInfo -> SoundData);
  138.     FreeVec(SoundInfo);
  139. }
  140.  
  141.     /* LoadSound(STRPTR Name):
  142.      *
  143.      *    Load a sound file from disk.
  144.      */
  145.  
  146. struct SoundInfo * __regargs
  147. LoadSound(STRPTR Name,BYTE Warn)
  148. {
  149.     struct SoundInfo    *SoundInfo = NULL;
  150.     struct IFFHandle    *Handle;
  151.  
  152.         /* Allocate IFF handle for reading. */
  153.  
  154.     if(Handle = AllocIFF())
  155.     {
  156.             /* Open a standard DOS stream. */
  157.  
  158.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  159.         {
  160.                 /* Say it's a DOS stream. */
  161.  
  162.             InitIFFasDOS(Handle);
  163.  
  164.                 /* Open the file for reading. */
  165.  
  166.             if(!OpenIFF(Handle,IFFF_READ))
  167.             {
  168.                 ULONG SoundStops[3 * 2] =
  169.                 {
  170.                     ID_8SVX,ID_VHDR,
  171.                     ID_8SVX,ID_CHAN,
  172.                     ID_8SVX,ID_BODY
  173.                 };
  174.  
  175.                     /* Mark the chunks to stop at. */
  176.  
  177.                 if(!StopChunks(Handle,SoundStops,3))
  178.                 {
  179.                     struct ContextNode    *Chunk;
  180.                     Voice8Header         Header;
  181.                     UBYTE             Compression;
  182.                     SampleType         Channel    = SAMPLE_STEREO;
  183.                     BYTE             SingleChannel    = TRUE;
  184.  
  185.                         /* Clear the voice header. */
  186.  
  187.                     memset(&Header,0,sizeof(Voice8Header));
  188.  
  189.                         /* Scan for data... */
  190.  
  191.                     while(!ParseIFF(Handle,IFFPARSE_SCAN))
  192.                     {
  193.                         Chunk = CurrentChunk(Handle);
  194.  
  195.                             /* What did we find? */
  196.  
  197.                         switch(Chunk -> cn_ID)
  198.                         {
  199.                                 /* Looks like the basic voice header. */
  200.  
  201.                             case ID_VHDR:
  202.  
  203.                                     /* Read the header. */
  204.  
  205.                                 if(ReadChunkRecords(Handle,&Header,MIN(Chunk -> cn_Size,sizeof(Voice8Header)),1) == 1)
  206.                                 {
  207.                                         /* Compression type supported? */
  208.  
  209.                                     if(Header . sCompression == sCmpNone || Header . sCompression == sCmpFibDelta)
  210.                                     {
  211.                                             /* Allocate the sound handle. */
  212.  
  213.                                         if(SoundInfo = (struct SoundInfo *)AllocVec(sizeof(struct SoundInfo),MEMF_ANY | MEMF_CLEAR))
  214.                                         {
  215.                                                 /* Install the rate, volume and length. */
  216.  
  217.                                             SoundInfo -> Rate    = SysBase -> ex_EClockFrequency * 5 / Header . samplesPerSec;
  218.                                             SoundInfo -> Length    = Header . oneShotHiSamples ? Header . oneShotHiSamples : Header . repeatHiSamples;
  219.                                             SoundInfo -> Volume    = (Header . volume * MAX_VOLUME) / Unity;
  220.  
  221.                                                 /* Remember compression mode. */
  222.  
  223.                                             Compression        = Header . sCompression;
  224.                                         }
  225.                                     }
  226.                                 }
  227.  
  228.                                 break;
  229.  
  230.                                 /* Looks like sound channel information. */
  231.  
  232.                             case ID_CHAN:
  233.  
  234.                                     /* Do we have a handle to manage it? */
  235.  
  236.                                 if(SoundInfo)
  237.                                 {
  238.                                         /* Read the channel information. */
  239.  
  240.                                     if(ReadChunkRecords(Handle,&Channel,MIN(Chunk -> cn_Size,sizeof(SampleType)),1) == 1)
  241.                                     {
  242.                                             /* Stereo sound file? */
  243.  
  244.                                         if(Channel == SAMPLE_STEREO)
  245.                                             SingleChannel = FALSE;
  246.                                     }
  247.                                     else
  248.                                     {
  249.                                         FreeVec(SoundInfo);
  250.  
  251.                                         SoundInfo = NULL;
  252.                                     }
  253.                                 }
  254.  
  255.                                 break;
  256.  
  257.                                 /* Looks like the sound body data. */
  258.  
  259.                             case ID_BODY:
  260.  
  261.                                     /* Do we have sound handle to manage it? */
  262.  
  263.                                 if(SoundInfo)
  264.                                 {
  265.                                     BYTE Success = FALSE;
  266.  
  267.                                         /* Uncompressed raw data? */
  268.  
  269.                                     if(Compression == sCmpNone)
  270.                                     {
  271.                                         ULONG Length = MIN(Chunk -> cn_Size,SoundInfo -> Length);
  272.  
  273.                                             /* Allocate a buffer. */
  274.  
  275.                                         if(SoundInfo -> SoundData = AllocVec(Length,MEMF_ANY))
  276.                                         {
  277.                                                 /* Read the data. */
  278.  
  279.                                             if(ReadChunkRecords(Handle,SoundInfo -> SoundData,Length,1) == 1)
  280.                                             {
  281.                                                     /* Store the actual length. */
  282.  
  283.                                                 SoundInfo -> Length = Length;
  284.  
  285.                                                 Success = TRUE;
  286.                                             }
  287.                                             else
  288.                                                 FreeVec(SoundInfo -> SoundData);
  289.                                         }
  290.                                     }
  291.                                     else
  292.                                     {
  293.                                         ULONG     Length = Chunk -> cn_Size;
  294.                                         UBYTE    *TempBuffer;
  295.  
  296.                                             /* Allocate a temporary decompression buffer. */
  297.  
  298.                                         if(TempBuffer = (UBYTE *)AllocVec(Length,MEMF_ANY))
  299.                                         {
  300.                                                 /* Read the compressed data. */
  301.  
  302.                                             if(ReadChunkRecords(Handle,TempBuffer,Length,1) == 1)
  303.                                             {
  304.                                                     /* Allocate space for the uncompressed data. */
  305.  
  306.                                                 if(SoundInfo -> SoundData = AllocVec((Length - 2) * 2,MEMF_ANY))
  307.                                                 {
  308.                                                         /* Stereo sound file? */
  309.  
  310.                                                     if(!SingleChannel && Channel == SAMPLE_STEREO)
  311.                                                     {
  312.                                                         UBYTE *Data = SoundInfo -> SoundData;
  313.  
  314.                                                             /* Unpack the stereo sound. */
  315.  
  316.                                                         DeltaUnpack(TempBuffer,               Length / 2,Data);
  317.                                                         DeltaUnpack(TempBuffer + (Length / 2),Length / 2,Data + (Length - 4));
  318.  
  319.                                                             /* Remember the sound length. */
  320.  
  321.                                                         SoundInfo -> Length = (Length - 4) * 2;
  322.                                                     }
  323.                                                     else
  324.                                                     {
  325.                                                             /* Unpack the mono sound. */
  326.  
  327.                                                         DeltaUnpack(TempBuffer,Length,SoundInfo -> SoundData);
  328.  
  329.                                                             /* Remember the sound length. */
  330.  
  331.                                                         SoundInfo -> Length = (Length - 2) * 2;
  332.                                                     }
  333.  
  334.                                                     Success = TRUE;
  335.                                                 }
  336.                                             }
  337.  
  338.                                             FreeVec(TempBuffer);
  339.                                         }
  340.                                     }
  341.  
  342.                                     if(!Success)
  343.                                     {
  344.                                         FreeVec(SoundInfo);
  345.  
  346.                                         SoundInfo = NULL;
  347.                                     }
  348.                                 }
  349.  
  350.                                 break;
  351.                         }
  352.                     }
  353.  
  354.                         /* Did we get what we wanted? */
  355.  
  356.                     if(SoundInfo)
  357.                     {
  358.                             /* Any sound data allocated? */
  359.  
  360.                         if(SoundInfo -> SoundData)
  361.                         {
  362.                             UBYTE *Data = SoundInfo -> SoundData;
  363.  
  364.                                 /* Which kind of sound file did
  365.                                  * we read?
  366.                                  */
  367.  
  368.                             switch(Channel)
  369.                             {
  370.                                     /* Left channel only. */
  371.  
  372.                                 case SAMPLE_LEFT:
  373.  
  374.                                     SoundInfo -> LeftData = Data;
  375.                                     break;
  376.  
  377.                                     /* Right channel only. */
  378.  
  379.                                 case SAMPLE_RIGHT:
  380.  
  381.                                     SoundInfo -> RightData = Data;
  382.                                     break;
  383.  
  384.                                     /* Two stereo channels. */
  385.  
  386.                                 case SAMPLE_STEREO:
  387.  
  388.                                         /* One sound mapped to two voices. */
  389.  
  390.                                     if(SingleChannel)
  391.                                         SoundInfo -> LeftData = SoundInfo -> RightData = Data;
  392.                                     else
  393.                                     {
  394.                                             /* Split the voice data. */
  395.  
  396.                                         SoundInfo -> Length    = SoundInfo -> Length / 2;
  397.  
  398.                                         SoundInfo -> LeftData    = Data;
  399.                                         SoundInfo -> RightData    = Data + SoundInfo -> Length;
  400.                                     }
  401.  
  402.                                     break;
  403.                             }
  404.                         }
  405.                         else
  406.                         {
  407.                             FreeVec(SoundInfo);
  408.  
  409.                             SoundInfo = NULL;
  410.                         }
  411.                     }
  412.                 }
  413.  
  414.                 CloseIFF(Handle);
  415.             }
  416.  
  417.             Close(Handle -> iff_Stream);
  418.         }
  419.  
  420.         FreeIFF(Handle);
  421.     }
  422.  
  423.         /* Successful? */
  424.  
  425.     if(SoundInfo)
  426.         strcpy(SoundInfo -> Name,Name);
  427.     else
  428.     {
  429.         if(Warn)
  430.             MyEasyRequest(Window,LocaleString(MSG_TERMSOUND_COULD_NOT_LOAD_SOUND_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Name);
  431.     }
  432.  
  433.     return(SoundInfo);
  434. }
  435.  
  436.     /* ReplaySound():
  437.      *
  438.      *    Replay sound with given information (doubly-buffered).
  439.      */
  440.  
  441. STATIC VOID __inline
  442. ReplaySound(struct SoundInfo *SoundInfo,struct IOAudio *SoundControlRequest,struct IOAudio *SoundRequestLeft,struct IOAudio *SoundRequestRight,struct BufferInfo *BufferInfo)
  443. {
  444.     UBYTE    *Left    = SoundInfo -> LeftData,
  445.         *Right    = SoundInfo -> RightData;
  446.     ULONG     Size    = SoundInfo -> Length,Length;
  447.     WORD     Base    = 0;
  448.  
  449.     Length = MIN(BUFFER_SIZE,Size);
  450.  
  451.     Size -= Length;
  452.  
  453.         /* Left channel available? */
  454.  
  455.     if(!(((ULONG)SoundRequestLeft -> ioa_Request . io_Unit) & (LEFT0F | LEFT1F)))
  456.         Left = NULL;
  457.  
  458.         /* Right channel available? */
  459.  
  460.     if(!(((ULONG)SoundRequestRight -> ioa_Request . io_Unit) & (RIGHT0F | RIGHT1F)))
  461.         Right = NULL;
  462.  
  463.         /* Fill up left buffer. */
  464.  
  465.     if(Left)
  466.     {
  467.         CopyMem(Left,BufferInfo[Base] . Buffer,Length);
  468.  
  469.         BufferInfo[Base] . Size = Length;
  470.  
  471.         Left += Length;
  472.     }
  473.  
  474.         /* Fill up right buffer. */
  475.  
  476.     if(Right)
  477.     {
  478.         CopyMem(Right,BufferInfo[Base + 2] . Buffer,Length);
  479.  
  480.         BufferInfo[Base + 2] . Size = Length;
  481.  
  482.         Right += Length;
  483.     }
  484.  
  485.         /* Process sound data. */
  486.  
  487.     do
  488.     {
  489.             /* Block both channels. */
  490.  
  491.         SoundControlRequest -> ioa_Request . io_Command = CMD_STOP;
  492.  
  493.         SendIO(SoundControlRequest);
  494.         WaitIO(SoundControlRequest);
  495.  
  496.             /* Any data for the left channel? */
  497.  
  498.         if(Left)
  499.         {
  500.             SoundRequestLeft -> ioa_Request . io_Command    = CMD_WRITE;
  501.             SoundRequestLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  502.             SoundRequestLeft -> ioa_Period            = SoundInfo -> Rate;
  503.             SoundRequestLeft -> ioa_Volume            = SoundInfo -> Volume;
  504.             SoundRequestLeft -> ioa_Cycles            = 1;
  505.             SoundRequestLeft -> ioa_Data            = BufferInfo[Base] . Buffer;
  506.             SoundRequestLeft -> ioa_Length            = BufferInfo[Base] . Size;
  507.  
  508.                 /* Get the left channel going. */
  509.  
  510.             BeginIO(SoundRequestLeft);
  511.         }
  512.  
  513.             /* Any data for the right channel? */
  514.  
  515.         if(Right)
  516.         {
  517.             SoundRequestRight -> ioa_Request . io_Command    = CMD_WRITE;
  518.             SoundRequestRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  519.             SoundRequestRight -> ioa_Period            = SoundInfo -> Rate;
  520.             SoundRequestRight -> ioa_Volume            = SoundInfo -> Volume;
  521.             SoundRequestRight -> ioa_Cycles            = 1;
  522.             SoundRequestRight -> ioa_Data            = BufferInfo[Base + 2] . Buffer;
  523.             SoundRequestRight -> ioa_Length            = BufferInfo[Base + 2] . Size;
  524.  
  525.                 /* Get the right channel going. */
  526.  
  527.             BeginIO(SoundRequestRight);
  528.         }
  529.  
  530.             /* Start up both channels synchronously... */
  531.  
  532.         SoundControlRequest -> ioa_Request . io_Command = CMD_START;
  533.  
  534.         SendIO(SoundControlRequest);
  535.         WaitIO(SoundControlRequest);
  536.  
  537.             /* Grab the other buffers. */
  538.  
  539.         Base ^= 1;
  540.  
  541.             /* Still any data left? */
  542.  
  543.         if(Size)
  544.         {
  545.                 /* Cut off the next slice. */
  546.  
  547.             Length = MIN(BUFFER_SIZE,Size);
  548.  
  549.             Size -= Length;
  550.  
  551.                 /* Left channel available? */
  552.  
  553.             if(Left)
  554.             {
  555.                 CopyMem(Left,BufferInfo[Base] . Buffer,Length);
  556.  
  557.                 BufferInfo[Base] . Size = Length;
  558.  
  559.                 Left += Length;
  560.             }
  561.  
  562.                 /* Right channel available? */
  563.  
  564.             if(Right)
  565.             {
  566.                 CopyMem(Right,BufferInfo[Base + 2] . Buffer,Length);
  567.  
  568.                 BufferInfo[Base + 2] . Size = Length;
  569.  
  570.                 Right += Length;
  571.             }
  572.  
  573.                 /* Last slice eaten? */
  574.  
  575.             if(!Size)
  576.             {
  577.                     /* Wait for sounds to terminate. */
  578.  
  579.                 if(Left)
  580.                     WaitIO(SoundRequestLeft);
  581.  
  582.                 if(Right)
  583.                     WaitIO(SoundRequestRight);
  584.  
  585.                     /* Block both channels. */
  586.  
  587.                 SoundControlRequest -> ioa_Request . io_Command = CMD_STOP;
  588.  
  589.                 SendIO(SoundControlRequest);
  590.                 WaitIO(SoundControlRequest);
  591.  
  592.                     /* Any data for the left channel? */
  593.  
  594.                 if(Left)
  595.                 {
  596.                     SoundRequestLeft -> ioa_Request . io_Command    = CMD_WRITE;
  597.                     SoundRequestLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  598.                     SoundRequestLeft -> ioa_Period            = SoundInfo -> Rate;
  599.                     SoundRequestLeft -> ioa_Volume            = SoundInfo -> Volume;
  600.                     SoundRequestLeft -> ioa_Cycles            = 1;
  601.                     SoundRequestLeft -> ioa_Data            = BufferInfo[Base] . Buffer;
  602.                     SoundRequestLeft -> ioa_Length            = BufferInfo[Base] . Size;
  603.  
  604.                         /* Get the left channel going. */
  605.  
  606.                     BeginIO(SoundRequestLeft);
  607.                 }
  608.  
  609.                     /* Any data for the right channel? */
  610.  
  611.                 if(Right)
  612.                 {
  613.                     SoundRequestRight -> ioa_Request . io_Command    = CMD_WRITE;
  614.                     SoundRequestRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  615.                     SoundRequestRight -> ioa_Period            = SoundInfo -> Rate;
  616.                     SoundRequestRight -> ioa_Volume            = SoundInfo -> Volume;
  617.                     SoundRequestRight -> ioa_Cycles            = 1;
  618.                     SoundRequestRight -> ioa_Data            = BufferInfo[Base + 2] . Buffer;
  619.                     SoundRequestRight -> ioa_Length            = BufferInfo[Base + 2] . Size;
  620.  
  621.                         /* Get the right channel going. */
  622.  
  623.                     BeginIO(SoundRequestRight);
  624.                 }
  625.  
  626.                     /* Start up both channels synchronously... */
  627.  
  628.                 SoundControlRequest -> ioa_Request . io_Command = CMD_START;
  629.  
  630.                 SendIO(SoundControlRequest);
  631.                 WaitIO(SoundControlRequest);
  632.             }
  633.         }
  634.  
  635.             /* Wait for sounds to terminate. */
  636.  
  637.         if(Left)
  638.             WaitIO(SoundRequestLeft);
  639.  
  640.         if(Right)
  641.             WaitIO(SoundRequestRight);
  642.     }
  643.     while(Size);
  644. }
  645.  
  646.     /* PlaySound(struct SoundInfo *SoundInfo):
  647.      *
  648.      *    Replay a sound.
  649.      */
  650.  
  651. VOID __regargs
  652. PlaySound(struct SoundInfo *SoundInfo)
  653. {
  654.     struct BufferInfo *BufferInfo;
  655.  
  656.         /* Allocate sound buffers. */
  657.  
  658.     if(BufferInfo = (struct BufferInfo *)AllocVec(4 * sizeof(struct BufferInfo),MEMF_CHIP))
  659.     {
  660.         struct MsgPort *SoundPort;
  661.  
  662.             /* Allocate an io replyport. */
  663.  
  664.         if(SoundPort = CreateMsgPort())
  665.         {
  666.             struct IOAudio *SoundControlRequest;
  667.  
  668.                 /* Allocate the big sound control request. */
  669.  
  670.             if(SoundControlRequest = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  671.             {
  672.                 struct IOAudio *SoundRequestLeft;
  673.  
  674.                     /* Allocate the left channel sound request. */
  675.  
  676.                 if(SoundRequestLeft = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  677.                 {
  678.                     struct IOAudio *SoundRequestRight;
  679.  
  680.                         /* Allocate the right channel sound request. */
  681.  
  682.                     if(SoundRequestRight = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  683.                     {
  684.                         STATIC UBYTE TwoChannels[] =
  685.                         {
  686.                             LEFT0F | RIGHT0F,
  687.                             LEFT0F | RIGHT1F,
  688.                             LEFT1F | RIGHT0F,
  689.                             LEFT1F | RIGHT1F
  690.                         };
  691.  
  692.                         STATIC UBYTE LeftChannel[] =
  693.                         {
  694.                             LEFT0F,
  695.                             LEFT1F
  696.                         };
  697.  
  698.                         STATIC UBYTE RightChannel[] =
  699.                         {
  700.                             RIGHT0F,
  701.                             RIGHT1F
  702.                         };
  703.  
  704.                         UBYTE    *AllocationMap;
  705.                         LONG     AllocationSize;
  706.  
  707.                             /* Determine the correct channel
  708.                              * allocation map.
  709.                              */
  710.  
  711.                         if(SoundInfo -> LeftData)
  712.                         {
  713.                             if(SoundInfo -> RightData)
  714.                             {
  715.                                 AllocationMap    = TwoChannels;
  716.                                 AllocationSize    = sizeof(TwoChannels);
  717.                             }
  718.                             else
  719.                             {
  720.                                 AllocationMap    = LeftChannel;
  721.                                 AllocationSize    = sizeof(LeftChannel);
  722.                             }
  723.                         }
  724.                         else
  725.                         {
  726.                             AllocationMap    = RightChannel;
  727.                             AllocationSize    = sizeof(RightChannel);
  728.                         }
  729.  
  730.                             /* Set up for sound channel allocation. */
  731.  
  732.                         SoundControlRequest -> ioa_Request . io_Message . mn_Node . ln_Pri    = 80;
  733.                         SoundControlRequest -> ioa_Request . io_Command                = ADCMD_ALLOCATE;
  734.                         SoundControlRequest -> ioa_Request . io_Flags                = ADIOF_NOWAIT | ADIOF_PERVOL;
  735.                         SoundControlRequest -> ioa_Data                        = AllocationMap;
  736.                         SoundControlRequest -> ioa_Length                    = AllocationSize;
  737.  
  738.                             /* Open audio.device, allocating the sound
  739.                              * channels on the fly.
  740.                              */
  741.  
  742.                         if(!OpenDevice(AUDIONAME,NULL,SoundControlRequest,NULL))
  743.                         {
  744.                                 /* Clone the sound control request. */
  745.  
  746.                             CopyMem(SoundControlRequest,SoundRequestLeft,    sizeof(struct IOAudio));
  747.                             CopyMem(SoundControlRequest,SoundRequestRight,    sizeof(struct IOAudio));
  748.  
  749.                                 /* Separate the channels. */
  750.  
  751.                             SoundRequestLeft  -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestLeft  -> ioa_Request . io_Unit & (LEFT0F  | LEFT1F));
  752.                             SoundRequestRight -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestRight -> ioa_Request . io_Unit & (RIGHT0F | RIGHT1F));
  753.  
  754.                                 /* Replay the sound... */
  755.  
  756.                             ReplaySound(SoundInfo,SoundControlRequest,SoundRequestLeft,SoundRequestRight,BufferInfo);
  757.  
  758.                                 /* Do the big cleanup. */
  759.  
  760.                             CloseDevice(SoundControlRequest);
  761.                         }
  762.  
  763.                         DeleteIORequest(SoundRequestRight);
  764.                     }
  765.  
  766.                     DeleteIORequest(SoundRequestLeft);
  767.                 }
  768.  
  769.                 DeleteIORequest(SoundControlRequest);
  770.             }
  771.  
  772.             DeleteMsgPort(SoundPort);
  773.         }
  774.  
  775.         FreeVec(BufferInfo);
  776.     }
  777. }
  778.  
  779.     /* SoundLoad(WORD Sound,BYTE Warn):
  780.      *
  781.      *    Loads or frees a sound slot.
  782.      */
  783.  
  784. STATIC BYTE __regargs
  785. SoundLoad(WORD Sound,BYTE Warn)
  786. {
  787.     struct SoundInfo    **Info = &SoundSlot[Sound];
  788.     STRPTR            Name;
  789.     BYTE            Success = FALSE;
  790.  
  791.         /* Which sound file name are we to pick? */
  792.  
  793.     switch(Sound)
  794.     {
  795.         case SOUND_BELL:
  796.  
  797.             Name = SoundConfig . BellFile;
  798.             break;
  799.  
  800.         case SOUND_CONNECT:
  801.  
  802.             Name = SoundConfig . ConnectFile;
  803.             break;
  804.  
  805.         case SOUND_DISCONNECT:
  806.  
  807.             Name = SoundConfig . DisconnectFile;
  808.             break;
  809.  
  810.         case SOUND_GOODTRANSFER:
  811.  
  812.             Name = SoundConfig . GoodTransferFile;
  813.             break;
  814.  
  815.         case SOUND_BADTRANSFER:
  816.  
  817.             Name = SoundConfig . BadTransferFile;
  818.             break;
  819.  
  820.         case SOUND_RING:
  821.  
  822.             Name = SoundConfig . RingFile;
  823.             break;
  824.  
  825.         case SOUND_VOICE:
  826.  
  827.             Name = SoundConfig . VoiceFile;
  828.             break;
  829.     }
  830.  
  831.         /* Is a file name available? */
  832.  
  833.     if(Name[0])
  834.     {
  835.             /* Sound slot already initialized? */
  836.  
  837.         if(*Info)
  838.         {
  839.                 /* Did the file name change? */
  840.  
  841.             if(Stricmp((*Info) -> Name,Name))
  842.             {
  843.                     /* Free the sound slot. */
  844.  
  845.                 FreeSound(*Info);
  846.  
  847.                     /* Try to load the sound slot. */
  848.  
  849.                 if(*Info = LoadSound(Name,Warn))
  850.                 {
  851.                         /* Remember the file name. */
  852.  
  853.                     strcpy((*Info) -> Name,Name);
  854.  
  855.                     Success = TRUE;
  856.                 }
  857.             }
  858.             else
  859.                 Success = TRUE;
  860.         }
  861.         else
  862.         {
  863.                 /* Try to load the sound slot. */
  864.  
  865.             if(*Info = LoadSound(Name,Warn))
  866.             {
  867.                     /* Remember the file name. */
  868.  
  869.                 strcpy((*Info) -> Name,Name);
  870.  
  871.                 Success = TRUE;
  872.             }
  873.         }
  874.     }
  875.     else
  876.     {
  877.             /* Does the slot still contain any sound? */
  878.  
  879.         if(*Info)
  880.         {
  881.                 /* Free the slot. */
  882.  
  883.             FreeSound(*Info);
  884.  
  885.             *Info = NULL;
  886.         }
  887.  
  888.         Success = TRUE;
  889.     }
  890.  
  891.     return(Success);
  892. }
  893.  
  894.     /* SoundServer(VOID):
  895.      *
  896.      *    Replay a sound.
  897.      */
  898.  
  899. STATIC VOID __saveds
  900. SoundServer(VOID)
  901. {
  902.     LONG Sound = (LONG)SysBase -> ThisTask -> tc_UserData;
  903.  
  904.         /* Get exclusive access to the sound slots. */
  905.  
  906.     ObtainSemaphore(SoundSemaphore);
  907.  
  908.         /* Replay the sound. */
  909.  
  910.     PlaySound(SoundSlot[Sound]);
  911.  
  912.     Forbid();
  913.  
  914.         /* Release access to the sound slots. */
  915.  
  916.     ReleaseSemaphore(SoundSemaphore);
  917.  
  918.         /* Remove ourselves. */
  919.  
  920.     RemTask(NULL);
  921. }
  922.  
  923.     /* SoundExit():
  924.      *
  925.      *    Free allocated sound resources.
  926.      */
  927.  
  928. VOID
  929. SoundExit()
  930. {
  931.     WORD i;
  932.  
  933.         /* Access semaphore available? */
  934.  
  935.     if(SoundSemaphore)
  936.     {
  937.         ObtainSemaphore(SoundSemaphore);
  938.  
  939.         ReleaseSemaphore(SoundSemaphore);
  940.  
  941.         FreeVec(SoundSemaphore);
  942.  
  943.         SoundSemaphore = NULL;
  944.     }
  945.  
  946.         /* Free the slots. */
  947.  
  948.     for(i = 0 ; i < SOUND_COUNT ; i++)
  949.     {
  950.         if(SoundSlot[i])
  951.         {
  952.             FreeSound(SoundSlot[i]);
  953.  
  954.             SoundSlot[i] = NULL;
  955.         }
  956.     }
  957. }
  958.  
  959.     /* SoundInit():
  960.      *
  961.      *    Allocate resources required for sound replaying.
  962.      */
  963.  
  964. VOID
  965. SoundInit()
  966. {
  967.         /* Sound access semaphore available? */
  968.  
  969.     if(SoundSemaphore)
  970.     {
  971.         ObtainSemaphore(SoundSemaphore);
  972.         ReleaseSemaphore(SoundSemaphore);
  973.     }
  974.     else
  975.     {
  976.         if(SoundSemaphore = (struct SignalSemaphore *)AllocVec(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
  977.             InitSemaphore(SoundSemaphore);
  978.     }
  979.  
  980.         /* Preload sounds if necessary. */
  981.  
  982.     if(SoundSemaphore && SoundConfig . Preload)
  983.     {
  984.         WORD i;
  985.  
  986.         for(i = 0 ; i < SOUND_COUNT ; i++)
  987.             SoundLoad(i,TRUE);
  988.     }
  989. }
  990.  
  991.     /* SoundPlay(WORD Sound):
  992.      *
  993.      *    Play a certain sound slot.
  994.      */
  995.  
  996. VOID
  997. SoundPlay(WORD Sound)
  998. {
  999.         /* Sound access semaphore available? */
  1000.  
  1001.     if(SoundSemaphore)
  1002.     {
  1003.             /* If to replay a bell sound, check to see
  1004.              * if we are currently playing a different
  1005.              * sound.
  1006.              */
  1007.  
  1008.         if(Sound == SOUND_BELL)
  1009.         {
  1010.             if(!AttemptSemaphore(SoundSemaphore))
  1011.                 return;
  1012.         }
  1013.         else
  1014.             ObtainSemaphore(SoundSemaphore);
  1015.  
  1016.         ReleaseSemaphore(SoundSemaphore);
  1017.  
  1018.             /* Release any other sound if necessary. */
  1019.  
  1020.         if(!SoundConfig . Preload)
  1021.         {
  1022.             WORD i;
  1023.  
  1024.             for(i = 0 ; i < SOUND_COUNT ; i++)
  1025.             {
  1026.                 if(i != Sound && SoundSlot[i])
  1027.                 {
  1028.                     FreeSound(SoundSlot[i]);
  1029.  
  1030.                     SoundSlot[i] = NULL;
  1031.                 }
  1032.             }
  1033.         }
  1034.  
  1035.             /* Load the sound slot. */
  1036.  
  1037.         SoundLoad(Sound,FALSE);
  1038.  
  1039.             /* Slot filled? */
  1040.  
  1041.         if(SoundSlot[Sound])
  1042.         {
  1043.             struct Task    *SoundTask;
  1044.             LONG         Pri = ThisProcess -> pr_Task . tc_Node . ln_Pri + 10;
  1045.  
  1046.                 /* Priority raised, check for limit. */
  1047.  
  1048.             if(Pri > 127)
  1049.                 Pri = 127;
  1050.  
  1051.             Forbid();
  1052.  
  1053.                 /* Fire off the sound server task. */
  1054.  
  1055.             if(SoundTask = CreateTask("term sound task",Pri,SoundServer,4096))
  1056.                 SoundTask -> tc_UserData = (APTR)Sound;
  1057.  
  1058.             Permit();
  1059.         }
  1060.         else
  1061.             Beep();
  1062.     }
  1063.     else
  1064.         Beep();
  1065. }
  1066.